#include "iic.h"

#include <STC8G.H>
#include <basic.h>
#include <uart.h>

#define I2C_TIMEOUT_TIMES 50 // 超时倍数

void Delay3us(void) //@11.0592MHz
{
    unsigned char data i;

    i = 9;
    while (--i)
        ;
}

void i2c_timeout_delay(void)
{
    delay(1);
}

void i2c_delay()
{
    Delay3us();
}

void i2c_start(i2c_handle_t *handler)
{
     handler->sda_ctrl( 1);
     handler->scl_ctrl( 1);
    i2c_delay();

     handler->sda_ctrl( 0);
     i2c_delay();
     handler->scl_ctrl( 0);
}

void i2c_stop(i2c_handle_t *handler)
{

    handler->sda_ctrl( 0);
    handler->scl_ctrl( 1);
    i2c_delay();
    handler->sda_ctrl( 1);
    i2c_delay();
}

void i2c_ack(i2c_handle_t *handler)
{
    // I2C_SCL_L();
    // I2C_SDA_L(); // SDA为低电平
    // i2c_delay();

    // I2C_SCL_H();
    // i2c_delay();
    // I2C_SCL_L();
    // I2C_SDA_H();

    handler->scl_ctrl( 0);
    handler->sda_ctrl( 0);
    i2c_delay();

    handler->scl_ctrl( 1);
    i2c_delay();
    handler->scl_ctrl( 0);
    handler->sda_ctrl( 1);
}

void i2c_nack(i2c_handle_t *handler)
{
    // I2C_SCL_L();
    // I2C_SDA_H(); // SDA为高电平
    // i2c_delay();

    // I2C_SCL_H();
    // i2c_delay();
    // I2C_SCL_L();

    handler->scl_ctrl( 0);
    handler->sda_ctrl( 1);
    i2c_delay();
    handler->scl_ctrl( 1);
    i2c_delay();
    handler->scl_ctrl( 0);
}

uint8_t i2c_wait_ack_fail(i2c_handle_t *handler)
{
    uint16_t time_temp = 0;

    // I2C_SCL_H();
    handler->scl_ctrl( 1);
    i2c_delay();
    while (handler->sda_read()) // 等待SDA为低电平
    {
        time_temp++;
        i2c_timeout_delay();
        if (time_temp > I2C_TIMEOUT_TIMES) // 超时则强制结束I2C通信
        {
            i2c_stop(handler);
            return 1;
        }
    }
    // I2C_SCL_L();
    handler->scl_ctrl( 0);
    return 0;
}

void i2c_write_byte_(i2c_handle_t *handler, uint8_t dat)
{
    uint8_t i = 0;

    // I2C_SCL_L();
    handler->scl_ctrl( 0);
    for (i = 0; i < 8; i++) // 循环8次将一个字节传出，先传高再传低位
    {
        if ((dat & 0x80) > 0)
            // I2C_SDA_H();
            handler->sda_ctrl( 1);
        else
            // I2C_SDA_L();
            handler->sda_ctrl( 0);
        dat <<= 1;
        // i2c_delay();
        // I2C_SCL_H();
        // i2c_delay();
        // I2C_SCL_L();
        // i2c_delay();

        i2c_delay();
        handler->scl_ctrl( 1);
        i2c_delay();
        handler->scl_ctrl( 0);
        i2c_delay();
    }
}

uint8_t i2c_read_byte(i2c_handle_t *handler, uint8_t ack)
{
    uint8_t i = 0, receive = 0;

    for (i = 0; i < 8; i++) // 循环8次将一个字节读出，先读高再传低位
    {
        // I2C_SCL_L();
        // i2c_delay();
        // I2C_SCL_H();
        // receive <<= 1;
        // if (I2C_SDA_Read())
        //     receive++;
        // i2c_delay();

        handler->scl_ctrl( 0);
        i2c_delay();
        handler->scl_ctrl( 1);
        receive <<= 1;
        if (handler->sda_read())
            receive++;
        i2c_delay();
    }
    if (!ack)
        i2c_nack(handler);
    else
        i2c_ack(handler);

    return receive;
}

int8_t i2c_probe(i2c_handle_t *handler, uint8_t DevAddress)
{
    i2c_start(handler);
    i2c_write_byte(handler, DevAddress << 1); // 转换为8位写地址（LSB=0）
    if (i2c_wait_ack_fail(handler) == 0)
    { // 0表示收到ACK（设备存在）
        i2c_stop(handler);
        return (int8_t)DevAddress; // 返回找到的地址
    }
    i2c_stop(handler);
    return -1; // 未找到返回-1
}

int8_t i2c_scan(i2c_handle_t *handler)
{
    uint8_t addr;
    for (addr = 0x03; addr <= 0x77; addr++)
    {
        int8_t result = i2c_probe(handler, addr);
        if (result != -1) // 找到有效地址
            return result;
    }
    return -1; // 未找到任何设备
}

bool i2c_begin_transmission(i2c_handle_t *handler)
{
    i2c_start(handler);
    if (handler->addr > 0)
    {
        i2c_write_byte(handler, handler->addr << 1); // 转换为8位写地址（LSB=0）
        if (i2c_wait_ack_fail(handler))
            return false;
    }

    return true;
}
bool i2c_end_transmission(i2c_handle_t *handler)
{
    i2c_stop(handler);
    return true;
}

bool i2c_write_byte(i2c_handle_t *handler, uint8_t dat)
{
    i2c_write_byte_(handler, dat);
    if (i2c_wait_ack_fail(handler))
        return false;
    return true;
}

uint16_t i2c_write(i2c_handle_t *handler, uint8_t *dat, uint16_t len)
{
    uint16_t l = 0;
    for (l = 0; l < len; l++)
    {
        i2c_write_byte_(handler, dat[l]);
        if (i2c_wait_ack_fail(handler))
            return l;
    }

    return l;
}
